const express = require('express');
const app = express();
const multer = require("multer");
const path = require('path');
const fs = require('fs');

const port = 3000;
const server = app.listen(port, () => {
    console.log('启动成功：', `http://127.0.0.1:${port}`);
});

const WebSocket = require('ws');
const WebSocketServer = WebSocket.Server;

// 创建 websocket 服务器
const wss = new WebSocketServer({
    server
});

// 连接数
let totalPeople = 0;

// 存所有连接上的用户
let clients = [];

// 消息缓存
let cacheTime = Number(new Date());
let cacheDatas = [];

// 用户信息(昵称和头像) 映射
let userInfoMap = {};

// 广播
wss.broadcast = function (data) {
    wss.clients.forEach(function (client) {
        client.send(data);
    });
};

// 服务器被客户端连接
wss.on('connection', (client) => {
    totalPeople++;

    // 大于30天，清空历史消息
    const curTime = Number(new Date());
    if (curTime > cacheTime + (30 * 24 * 60 * 60 * 1000)) {
        cacheDatas = [];
        cacheTime = curTime;
    }

    // 发送历史消息
    client.send(JSON.stringify({
        history: JSON.stringify(cacheDatas)
    }))
    // 广播
    wss.broadcast(JSON.stringify({
        totalPeople: totalPeople
    }));

    // 接收消息
    client.on('message', function (message) {
        let data = {};
        try {
            data = JSON.parse(message.toString());
        } catch (error) {
            data = null;
        }

        if (!data) return;

        let uuid = data.uuid;
        let {
            nickname,
            avatar
        } = userInfoMap[uuid] || {};
        if (!nickname) {
            nickname = getNickname();
            avatar = getAvatar();
            userInfoMap[uuid] = {
                nickname: nickname,
                avatar: avatar
            }
        }
        const newData = {
            totalPeople,
            uuid: uuid,
            nickname: nickname,
            avatar: avatar,
            content: data.content || '',
            image: data.image || '',
            createDate: Number(new Date())
        }

        // 悄悄话（不保存消息）
        if (!data.whispers) {
            cacheDatas.push(newData);
        }
        wss.broadcast(JSON.stringify(newData));
    });

    // 断开连接
    client.on('close', () => {
        totalPeople--;
        
        // 广播
        wss.broadcast(JSON.stringify({
            totalPeople: totalPeople
        }));
    })
})

// 随机得到用户昵称
function getNickname() {
    let s = ['大神', '大佬', '菜鸟', '渣渣', '学霸', '学神', '学者', '学渣', '初级摸鱼小能手', '中级摸鱼小能手', '摸鱼高手', '真的菜', '真像菜', '话痨', '不闻不问', '逆天而行', '大吃四方', '随风起舞', '寒风凛凛', '不知好歹'];
    let num = Math.floor(Math.random() * s.length);
    return s[num];
}

// 随机得到用户头像
function getAvatar() {
    let num = Math.ceil(Math.random() * 6);
    return `https://www.clluo.com/resource/images/avatar/${num}.png`;
}

/***********************************  HTTP ************************************************** */

app.use('*', (req, res, next) => {
    // 强缓存
    res.setHeader('Cache-Control', 'max-age=10'); // 设置缓存时长 = 当前时间 + max-age；优先级比Expires高
    res.setHeader('Expires', new Date(Date.now() + 10).toUTCString()); // 兼容低版本浏览器的缓存时长
    next();
})

app.use("/", express.static(path.join(__dirname, "/public")));
app.use("/resources", express.static(path.join(__dirname, "/resources")));

app.get("/", (req, res) => {
    const pageUrl = path.resolve(__dirname, './public/index.html');
    fs.readFile(pageUrl, (err, data) => {
        if (err) return res.end('404');

        res.writeHead(200, {
            'Content-Type': 'text/html; charset=utf8'
        });
        res.end(data.toString());
    })
})

// 清空聊天数据
app.get("/api/clear", (req, res) => {
    cacheDatas = [];
    return res.json({
        code: 0,
        msg: '已清除'
    })
});

// 获取用户信息
app.get('/api/getUserInfo', (req, res) => {
    const uuid = req.query.uuid;
    if (!uuid) {
        return res.json({
            code: -1,
            msg: '参数出错'
        })
    }

    let {
        nickname,
        avatar
    } = userInfoMap[uuid] || {};

    if (!nickname || !avatar) {
        nickname = getNickname();
        avatar = getAvatar();
        userInfoMap[uuid] = {
            nickname: nickname,
            avatar: avatar
        }
    }
    return res.json({
        code: 0,
        msg: '请求成功',
        data: {
            nickname,
            avatar
        }
    })
})

// 磁盘存储（上传文件） 
const storageImg = multer.diskStorage({
    //设置上传后文件路径
    destination: function (req, file, cb) {
        cb(null, './resources/images');
    },
    //给上传文件重命名，获取添加后缀名
    filename: function (req, file, cb) {
        const fileFormat = (file.originalname).split(".");
        cb(null, file.fieldname + '' + Date.now() + "." + fileFormat[fileFormat.length - 1]);
    }
});
app.use("/api/upload/image", multer({
    storage: storageImg
}).array("image"));

const log = require('./config/log');

// 上传图片
app.post('/api/upload/image', (req, res) => {
    // 判断发送的图片的相似度
    const pixelsA = '0000000111000011110110111111111111000011110000011100000100000000';
    const pixelsB = '1111111111000101111101111111011111101011100000010000000000100111';

    const pixels = req.body.similar || '';
    if (!pixels) {
        return res.json({
            code: -1,
            msg: '参数不完整'
        })
    }
    let tw = 8;
    let th = 8;

    let similarA = 0;
    for (var i = 0, len = tw * th; i < len; i++) {
        if (pixelsA[i] == pixels[i]) similarA++;
    }
    similarA = (similarA / (tw * th)) * 100;

    let similarB = 0;
    for (var i = 0, len = tw * th; i < len; i++) {
        if (pixelsB[i] == pixels[i]) similarB++;
    }
    similarB = (similarB / (tw * th)) * 100;

    let USER_AGENT = req.headers['user-agent'];
    let chromeIdx = USER_AGENT.indexOf('Chrome');
    let vesion = USER_AGENT.slice(chromeIdx + 7, chromeIdx + 9);

    let similar = Number(vesion) < 90 ? similarA : similarB;

    log('图片相似度数据：', JSON.stringify({
        SIMILAR_A: similarA,
        SIMILAR_B: similarB,
        PIXELS: pixels,
        IP: req.ip.replace('::ffff:', ''),
        VESION: vesion,
        USER_AGENT: USER_AGENT
    }))

    if (similar > 80 || similarA > 90 || similarB > 90) {
        return res.json({
            code: -1,
            msg: '此图片已被限制，不可发送'
        })
    }

    const files = req.files[0];
    fs.readFile(files.path, function (err, data) {
        if (err) {
            return res.json({
                code: -1,
                msg: "上传失败"
            });
        }

        return res.json({
            code: 0,
            msg: "上传成功",
            data: {
                path: files.path
            }
        });

    });
})